package uy.org.softtech.cssuite.entidad.sistema;

import static uy.org.softtech.cssuite.entidad.Entidad.SISTEMAS_NAMESPACE;
import static uy.org.softtech.cssuite.helpers.HelperFechaHora.fechaLarga;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;

import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.annotate.JsonRootName;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
import org.hibernate.annotations.Index;

import uy.org.softtech.cssuite.entidad.EntidadTraducible;
import uy.org.softtech.cssuite.helpers.HelperFechaHora;

/**
 * <p>Entidad que representa a una tarea programada. También mapea la declaración del tipo de dato XML 'tareaProgramada'.</p>
 * 
 * <p>El siguiente fragmento de esquema especifica el contenido esperado y representado por los atributos de esta clase.</p>
 *  
 * <pre>
 * &lt;xsd:complexType name="tareaProgramada">
 *  &lt;xsd:all>
 *   &lt;xsd:element name="id" type="xsd:ID"/>
 *   &lt;xsd:element name="estado" type="{http://cssuite.softtech.org.uy/esquemas/tipos}estadoTarea"/>
 *   &lt;xsd:element name="descripcion" type="{http://cssuite.softtech.org.uy/esquemas/tipos}texto"/>
 *   &lt;xsd:element name="ejecuciones" type="xsd:integer" default="0" />
 *   &lt;xsd:element name="exitosas" type="xsd:integer" default="0" />
 *   &lt;xsd:element name="fallidas" type="xsd:integer" default="0" />
 *   &lt;xsd:element name="horaComienzo" type="xsd:dateTime" />
 *   &lt;xsd:element name="horaFin" type="xsd:dateTime" />
 *   &lt;xsd:element name="horaUltimaExitosa" type="xsd:dateTime" />
 *   &lt;xsd:element name="horaUltimaFallida" type="xsd:dateTime" />
 *  &lt;/xsd:all>
 * &lt;/xsd:complexType>
 * 
 * </pre>
 *
 * @author fabian.lobo
 */
@Entity
@JsonRootName(value = "tarea")
@JsonSerialize(include = Inclusion.NON_NULL)
@Table(name = "CSS_TAREA")
@XmlSeeAlso({EntidadTraducible.class})
@XmlType(name = "tareaProgramada", namespace = SISTEMAS_NAMESPACE, propOrder = {})
public class Tarea extends EntidadTraducible implements Serializable {

	private static final long serialVersionUID = -1730913214380942566L;
	
	/**
	 * Enumerado para todos los posibles estado de la tarea.
	 * 
	 * @author fabian.lobo
	 */
	@XmlEnum
	@XmlType(name = "estadoTarea", namespace = SISTEMAS_NAMESPACE)
	public enum Estado {
		INACTIVA, ACTIVA, TERMINADA, CANCELADA
	}
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "ID_TAREA")
	@XmlElement(name = "id", namespace = SISTEMAS_NAMESPACE, required = true)
	private Long id;
	
	@Column(name = "ESTADO", length = 20, nullable = false)
	@Enumerated(EnumType.STRING)
	@XmlElement(name = "estado", namespace = SISTEMAS_NAMESPACE, required = true)
	private Estado estado;
	
	@Column(name = "INSTANCIA", nullable = false)
	@Index(name = "IDX_INSTANCIA")
	@JsonIgnore
	@XmlTransient
	private String instancia;
	
	@Column(name = "EJECUCIONES", nullable = false)
	@XmlElement(name = "ejecuciones", namespace = SISTEMAS_NAMESPACE, required = false, defaultValue = "0")
	private Integer ejecuciones = Integer.valueOf(0);
	
	@Column(name = "EXITOSAS", nullable = false)
	@XmlElement(name = "exitosas", namespace = SISTEMAS_NAMESPACE, required = false, defaultValue = "0")
	private Integer exitosas = Integer.valueOf(0);
	
	@Column(name = "FALLIDAS", nullable = false)
	@XmlElement(name = "fallidas", namespace = SISTEMAS_NAMESPACE, required = false, defaultValue = "0")
	private Integer fallidas = Integer.valueOf(0);
	
	@Column(name = "HORA_COMIENZO", nullable = true)
	@JsonIgnore
	@Temporal(TemporalType.TIMESTAMP)
	@XmlElement(name = "horaComienzo", namespace = SISTEMAS_NAMESPACE, required = false)
	private Date horaComienzo;
	
	@Column(name = "HORA_FIN", nullable = true)
	@JsonIgnore
	@Temporal(TemporalType.TIMESTAMP)
	@XmlElement(name = "horaFin", namespace = SISTEMAS_NAMESPACE, required = false)
	private Date horaFin;
	
	@Column(name = "HORA_ULTIMA_EXITOSA", nullable = true)
	@JsonIgnore
	@Temporal(TemporalType.TIMESTAMP)
	@XmlElement(name = "horaUltimaExitosa", namespace = SISTEMAS_NAMESPACE, required = false)
	private Date horaUltimaExitosa;
	
	@Column(name = "HORA_ULTIMA_FALLIDA", nullable = true)
	@JsonIgnore
	@Temporal(TemporalType.TIMESTAMP)
	@XmlElement(name = "horaUltimaFallida", namespace = SISTEMAS_NAMESPACE, required = false)
	private Date horaUltimaFallida;

	/*
	 *  GETTERS
	 */
	public Long getId() {
		return id;
	}
	public Estado getEstado() {
		return estado;
	}
	public String getInstancia() {
		return instancia;
	}
	public Integer getEjecuciones() {
		return ejecuciones;
	}
	public Integer getExitosas() {
		return exitosas;
	}
	public Integer getFallidas() {
		return fallidas;
	}
	public Date getHoraComienzo() {
		return horaComienzo;
	}
	public Date getHoraFin() {
		return horaFin;
	}
	public Date getHoraUltimaExitosa() {
		return horaUltimaExitosa;
	}
	public Date getHoraUltimaFallida() {
		return horaUltimaFallida;
	}

	/*
	 *  SETTERS
	 */
	public void setId(Long id) {
		this.id = id;
	}
	public void setEstado(Estado estado) {
		this.estado = estado;
	}
	public void setInstancia(String instancia) {
		this.instancia = instancia;
	}
	public void setEjecuciones(Integer ejecuciones) {
		this.ejecuciones = ejecuciones;
	}
	public void setExitosas(Integer exitosas) {
		this.exitosas = exitosas;
	}
	public void setFallidas(Integer fallidas) {
		this.fallidas = fallidas;
	}
	public void setHoraComienzo(Date horaComienzo) {
		this.horaComienzo = horaComienzo;
	}
	public void setHoraFin(Date horaFin) {
		this.horaFin = horaFin;
	}
	public void setHoraUltimaExitosa(Date horaUltimaExitosa) {
		this.horaUltimaExitosa = horaUltimaExitosa;
	}
	public void setHoraUltimaFallida(Date horaUltimaFallida) {
		this.horaUltimaFallida = horaUltimaFallida;
	}
	
	/*
	 *  CONVERSORES
	 */
	/**
	 * Convierte la hora de comienzo a texto
	 * 
	 * @author fabian.lobo
	 * @see HelperFechaHora#fechaLarga()
	 */
	@JsonProperty(value = "horaComienzo")
	public String convierteHoraComienzo() {
		return fechaLarga(getHoraComienzo());
	}
	
	/**
	 * Convierte la hora de fin a texto
	 * 
	 * @author fabian.lobo
	 * @see HelperFechaHora#fechaLarga()
	 */
	@JsonProperty(value = "horaFin")
	public String convierteHoraFin() {
		return fechaLarga(getHoraFin());
	}
	
	/**
	 * Convierte la hora de la última ejecución exitosa a texto
	 * 
	 * @author fabian.lobo
	 * @see HelperFechaHora#fechaLarga()
	 */
	@JsonProperty(value = "horaUltimaExitosa")
	public String convierteHoraUltimaExitosa() {
		return fechaLarga(getHoraUltimaExitosa());
	}
	
	/**
	 * Convierte la hora de la última ejecución fallida a texto
	 * 
	 * @author fabian.lobo
	 * @see HelperFechaHora#fechaLarga()
	 */
	@JsonProperty(value = "horaUltimaFallida")
	public String convierteHoraUltimaFallida() {
		return fechaLarga(getHoraUltimaFallida());
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 4;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		Tarea other = (Tarea) obj;
		if (id != null && other.id != null && id.equals(other.id)) {
			return true;
		}
		return false;
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("Permiso [");
		builder.append("id=" + getId() + ", ");
		builder.append("estado=" + getEstado() + ", ");
		builder.append("instancia=" + getInstancia() + ", ");
		builder.append("ejecuciones=" + getEjecuciones() + ", ");
		builder.append("exitosas=" + getExitosas() + ", ");
		builder.append("fallidas=" + getFallidas() + ", ");
		builder.append("horaComienzo=" + convierteHoraComienzo() + ", ");
		builder.append("horaFin=" + convierteHoraFin() + ", ");
		builder.append("horaUltimaExitosa=" + convierteHoraUltimaExitosa() + ", ");
		builder.append("horaUltimaFallida="  + convierteHoraUltimaFallida());
		builder.append("]");
		return builder.toString();
	}

	@Override
	public String toString(boolean incluirColecciones) {
		StringBuilder result = new StringBuilder(toString());
		
		if(incluirColecciones) {
			int offset = result.length() - 2;
			StringBuilder builder = new StringBuilder(", ");
			//builder.append("permissions=" + getPermissions());
			result.insert(offset, builder.toString());
		}	
				
		return result.toString();
	}

}
